"""
安全工具模块
提供安全相关功能
"""
import re
import hashlib
import hmac
import secrets
from typing import Optional
from html import escape

from flask import current_app, request

def sanitize_input(input_string: str, 
                  allowed_tags: Optional[list] = None,
                  max_length: Optional[int] = None) -> str:
    """
    清理用户输入
    
    Args:
        input_string: 输入字符串
        allowed_tags: 允许的HTML标签
        max_length: 最大长度
        
    Returns:
        str: 清理后的字符串
    """
    if not input_string:
        return ''
    
    # 限制长度
    if max_length and len(input_string) > max_length:
        input_string = input_string[:max_length]
    
    # 基本的HTML转义
    cleaned = escape(input_string)
    
    # 如果需要允许某些HTML标签，可以使用bleach等库
    # 这里进行简单的处理
    
    return cleaned.strip()

def escape_html(text: str) -> str:
    """
    HTML转义
    
    Args:
        text: 原始文本
        
    Returns:
        str: 转义后的文本
    """
    return escape(text)

def prevent_xss(text: str) -> str:
    """
    防止XSS攻击
    
    Args:
        text: 原始文本
        
    Returns:
        str: 安全的文本
    """
    # 移除危险的JavaScript协议
    text = re.sub(r'javascript:', '', text, flags=re.IGNORECASE)
    text = re.sub(r'vbscript:', '', text, flags=re.IGNORECASE)
    text = re.sub(r'data:', '', text, flags=re.IGNORECASE)
    
    # 移除事件处理器
    text = re.sub(r'on\w+=', '', text, flags=re.IGNORECASE)
    
    return text

def prevent_sql_injection(text: str) -> str:
    """
    防止SQL注入（基础防护）
    
    Args:
        text: 原始文本
        
    Returns:
        str: 安全的文本
    """
    # 移除常见的SQL注入关键词
    dangerous_patterns = [
        r'(\bSELECT\b|\bINSERT\b|\bUPDATE\b|\bDELETE\b|\bDROP\b|\bUNION\b)',
        r'(\bOR\b|\bAND\b)\s+\d+=\d+',
        r'(\bEXEC\b|\bEXECUTE\b|\bEXECSP\b)',
        r'--', r'/\*', r'\*/'
    ]
    
    for pattern in dangerous_patterns:
        text = re.sub(pattern, '', text, flags=re.IGNORECASE)
    
    return text

def generate_csrf_token() -> str:
    """
    生成CSRF令牌
    
    Returns:
        str: CSRF令牌
    """
    return secrets.token_urlsafe(32)

def verify_csrf_token(token: str, session_token: str) -> bool:
    """
    验证CSRF令牌
    
    Args:
        token: 请求中的令牌
        session_token: 会话中的令牌
        
    Returns:
        bool: 是否验证成功
    """
    if not token or not session_token:
        return False
    
    return hmac.compare_digest(token, session_token)

def generate_secure_hash(data: str, salt: Optional[str] = None) -> str:
    """
    生成安全哈希
    
    Args:
        data: 原始数据
        salt: 盐值
        
    Returns:
        str: 哈希值
    """
    if salt is None:
        salt = current_app.config.get('SECRET_KEY', 'default-salt')
    
    return hashlib.pbkdf2_hmac(
        'sha256',
        data.encode('utf-8'),
        salt.encode('utf-8'),
        100000  # 迭代次数
    ).hex()

def encrypt_data(data: str, key: Optional[str] = None) -> str:
    """
    加密数据（简单实现，生产环境应使用更安全的加密）
    
    Args:
        data: 原始数据
        key: 加密密钥
        
    Returns:
        str: 加密后的数据
    """
    if key is None:
        key = current_app.config.get('SECRET_KEY', 'default-key')
    
    # 这里应该使用真正的加密算法
    # 现在使用简单的XOR加密作为示例
    encrypted = ''.join(chr(ord(c) ^ ord(key[i % len(key)])) for i, c in enumerate(data))
    return encrypted.encode('utf-8').hex()

def decrypt_data(encrypted_data: str, key: Optional[str] = None) -> str:
    """
    解密数据
    
    Args:
        encrypted_data: 加密数据
        key: 解密密钥
        
    Returns:
        str: 解密后的数据
    """
    if key is None:
        key = current_app.config.get('SECRET_KEY', 'default-key')
    
    try:
        # 简单的XOR解密
        encrypted_bytes = bytes.fromhex(encrypted_data)
        decrypted = ''.join(chr(b ^ ord(key[i % len(key)])) for i, b in enumerate(encrypted_bytes))
        return decrypted
    except Exception:
        return ''

def validate_file_upload(filename: str, content_type: str, 
                        file_size: int) -> tuple[bool, str]:
    """
    验证文件上传
    
    Args:
        filename: 文件名
        content_type: 内容类型
        file_size: 文件大小
        
    Returns:
        tuple: (是否有效, 错误消息)
    """
    # 检查文件扩展名
    allowed_extensions = current_app.config.get('ALLOWED_EXTENSIONS', {})
    all_allowed = set()
    for ext_list in allowed_extensions.values():
        all_allowed.update(ext_list)
    
    file_ext = filename.rsplit('.', 1)[-1].lower() if '.' in filename else ''
    if file_ext not in all_allowed:
        return False, f"不支持的文件类型: {file_ext}"
    
    # 检查文件大小
    max_size = current_app.config.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024)
    if file_size > max_size:
        return False, f"文件大小超过限制: {file_size} > {max_size}"
    
    # 检查内容类型
    allowed_mime_types = current_app.config.get('ALLOWED_MIME_TYPES', [])
    if allowed_mime_types and content_type not in allowed_mime_types:
        return False, f"不支持的内容类型: {content_type}"
    
    return True, ""

def generate_secure_filename(filename: str) -> str:
    """
    生成安全的文件名
    
    Args:
        filename: 原始文件名
        
    Returns:
        str: 安全的文件名
    """
    import os
    from werkzeug.utils import secure_filename
    
    # 使用Werkzeug的secure_filename
    safe_name = secure_filename(filename)
    
    # 添加随机前缀防止冲突
    import uuid
    random_prefix = uuid.uuid4().hex[:8]
    
    return f"{random_prefix}_{safe_name}"

def check_password_strength(password: str) -> dict:
    """
    检查密码强度
    
    Args:
        password: 密码
        
    Returns:
        dict: 强度分析结果
    """
    result = {
        'score': 0,
        'strength': '非常弱',
        'feedback': []
    }
    
    if not password:
        return result
    
    # 长度评分
    if len(password) >= 8:
        result['score'] += 1
    if len(password) >= 12:
        result['score'] += 1
    
    # 字符类型评分
    has_upper = any(c.isupper() for c in password)
    has_lower = any(c.islower() for c in password)
    has_digit = any(c.isdigit() for c in password)
    has_special = any(not c.isalnum() for c in password)
    
    char_types = sum([has_upper, has_lower, has_digit, has_special])
    if char_types >= 3:
        result['score'] += 1
    if char_types == 4:
        result['score'] += 1
    
    # 常见模式检查
    common_patterns = ['123', 'abc', 'qwerty', 'password']
    if any(pattern in password.lower() for pattern in common_patterns):
        result['score'] = max(0, result['score'] - 1)
        result['feedback'].append('密码包含常见模式')
    
    # 确定强度等级
    if result['score'] >= 4:
        result['strength'] = '非常强'
    elif result['score'] >= 3:
        result['strength'] = '强'
    elif result['score'] >= 2:
        result['strength'] = '中等'
    elif result['score'] >= 1:
        result['strength'] = '弱'
    else:
        result['strength'] = '非常弱'
    
    # 提供改进建议
    if len(password) < 8:
        result['feedback'].append('密码长度至少8个字符')
    if not has_upper:
        result['feedback'].append('添加大写字母')
    if not has_lower:
        result['feedback'].append('添加小写字母')
    if not has_digit:
        result['feedback'].append('添加数字')
    if not has_special:
        result['feedback'].append('添加特殊字符')
    
    return result

def log_security_event(event_type: str, description: str, 
                      user_id: Optional[int] = None,
                      ip_address: Optional[str] = None,
                      user_agent: Optional[str] = None):
    """
    记录安全事件
    
    Args:
        event_type: 事件类型
        description: 事件描述
        user_id: 用户ID
        ip_address: IP地址
        user_agent: 用户代理
    """
    from app.utils.logging import get_logger
    
    logger = get_logger('stehub.security')
    
    log_data = {
        'event_type': event_type,
        'description': description,
        'user_id': user_id,
        'ip_address': ip_address or request.remote_addr,
        'user_agent': user_agent or request.user_agent.string
    }
    
    logger.warning("安全事件", extra=log_data)